// 注意:
// 不要传入空的数组到此接口中
#ifndef xpack_math_minimaxi
#define xpack_math_minimaxi
#pragma push_macro("xuser")
#undef  xuser
#define xuser mixc::math_minimaxi::inc
#include"define/base_type.hpp"
#include"interface/can_compare.hpp"
#include"interface/initializer_list.hpp"
#include"interface/unified_seq.hpp"
#include"macro/xexport.hpp"
#include"macro/xunlikely.hpp"
#include"utils/get_prop_value.hpp"
#include"utils/value_holder.hpp"
#pragma pop_macro("xuser")

namespace mixc::math_minimaxi::origin{
    // 避免使用 min/max 这个名称，因为会和一些平台宏函数重名
    template<class type>
    struct minimaxi_pair{
        type min_value;
        type max_value;
    };

    template<class type_t>
    // 不使用 type_t const &，因为如果参数是右值，
    // 那么生命周期达不到返回后的位置，这个在编译器开优化模式才能看到，调试模式会隐匿这个问题
    inline minimaxi_pair<type_t> minimaxi(type_t left, type_t right){
        return left < right ? minimaxi_pair<type_t>{ left, right } : minimaxi_pair<type_t>{ right, left };
    }

    template<class item_t, class list_t = inc::initializer_list<item_t>, class cmp_t = decltype(inc::default_compare<item_t>)>
    requires(inc::can_unified_seqlizex<list_t, item_t> and inc::can_compare<cmp_t, item_t>)
    inline minimaxi_pair<inc::value_holder<item_t>> minimaxix(list_t && list, cmp_t const & compare = inc::default_compare<item_t>){
        auto ary        = inc::unified_seq<list_t>(list);
        auto len        = ary->length();
        auto i_min      = uxx{};
        auto i_max      = uxx{};
        xunlikely(len == 0){
            return { {}, {} };
        }

        for(uxx i = 1; i < len; i++){
            auto & minv = ary[i_min];
            auto & maxv = ary[i_max];
            auto & curr = ary[i];
            if (compare(minv, curr) > 0){
                i_min   = i;
            }
            if (compare(maxv, curr) < 0){
                i_max   = i;
            }
        }
        return { { ary[i_min], i_min }, { ary[i_max], i_max } };
    }

    template<class item_t, class list_t = inc::initializer_list<item_t>, class cmp_t = decltype(inc::default_compare<item_t>)>
    requires(inc::can_unified_seqlizex<list_t, item_t> and inc::can_compare<cmp_t, item_t>)
    inline minimaxi_pair<item_t> minimaxi(list_t && list, cmp_t const & compare = inc::default_compare<item_t>){
        auto result = minimaxix<item_t, list_t, cmp_t>((list_t &&)list, compare);
        return minimaxi_pair<item_t>{ result.min_value->value, result.max_value->value };
    }

    // 这是个 dummy 接口，
    // 要求外部使用 inc::xminimaxi_field(type, field, list); 这种方式调用
    // 不要直接使用 xminimaxi_field() 宏
    template<class value_t>
    inline decltype(auto) xminimaxi_field(value_t && value){
        return (value_t &&)value;
    }

    // 同上
    template<class value_t>
    inline decltype(auto) xminimaxi_fieldx(value_t && value){
        return (value_t &&)value;
    }

    // 根多细节参考 math/maximum.hpp
    #define xminimaxi_field(TYPE,FIELD,...)                                                                                 \
        xminimaxi_field(([&](){                                                                                             \
            auto && [minv, maxv] = ::mixc::math_minimaxi::origin::minimaxi<TYPE>(__VA_ARGS__, xcmp_field(FIELD, TYPE));     \
            using item_t = decltype(::mixc::math_minimaxi::inc::get_prop_value(minv FIELD));                                \
            return ::mixc::math_minimaxi::origin::minimaxi_pair<item_t>{ minv FIELD, maxv FIELD };                          \
        })())

    #define xminimaxi_fieldx(TYPE,FIELD,...)                                                                                \
        xminimaxi_fieldx(([&](){                                                                                            \
            auto result = ::mixc::math_minimaxi::origin::minimaxix<TYPE>(__VA_ARGS__, xcmp_field(FIELD, TYPE));             \
            using item_t = decltype(::mixc::math_minimaxi::inc::get_prop_value(result.min_value->value() FIELD));           \
            using value_t = ::mixc::math_minimaxi::inc::value_holder<item_t>;                                               \
            if (result.min_value->is_hold_value){                                                                           \
                auto min_value = ::mixc::math_minimaxi::inc::get_prop_value(result.min_value->value() FIELD);               \
                auto max_value = ::mixc::math_minimaxi::inc::get_prop_value(result.max_value->value() FIELD);               \
                return ::mixc::math_minimaxi::origin::minimaxi_pair<value_t>{                                               \
                    { min_value, result.min_value->index },                                                                 \
                    { max_value, result.max_value->index },                                                                 \
                };                                                                                                          \
            }                                                                                                               \
            else{                                                                                                           \
                return ::mixc::math_minimaxi::origin::minimaxi_pair<value_t>{};                                             \
            }                                                                                                               \
        })())
}

#endif

// 示意外部可以不用包含 xcmp.hpp，可以直接使用
#include"macro/xcmp.hpp"
xexport_space(mixc::math_minimaxi::origin)